/**
 * File TimerAgent.java created by Pablo Díaz Fernández
 * on 27/10/2011 for the project supply-chain-simulator
 */
package org.lsk.pfc.scsim.model.agent;

import jade.core.AID;
import jade.core.Agent;

import java.util.List;

import org.lsk.pfc.scsim.model.behaviour.TimerCyclicBehaviour;
import org.lsk.pfc.scsim.model.exception.AgentException;
import org.lsk.pfc.scsim.model.util.AgentTableHelper;

/**
 * @author Pablo Díaz Fernández
 * 
 */
public final class TimerAgent extends Agent {

	/**
	 * Serial version ID.
	 */
	private static final long serialVersionUID = -334655263139669662L;

	/**
	 * Flag that indicates the request of end of execution.
	 */
	private boolean endOfExecution = false;

	/**
	 * Maximum number of simulation ticks.
	 */
	private int simulationHorizon = 0;

	/**
	 * Current time tick in the simulation.
	 */
	private long currentTick = 0;
	/**
	 * Number of agents that have sent EOE signal.
	 */
	private int eoeSent = 0;
	/**
	 * Number of agents that have sent EOT signal.
	 */
	private int eotSent = 0;

	/**
	 * Table of all syndicated agents.
	 */
	private AgentTableHelper syndicatedAgents;

	/**
	 * Constructor of the class.
	 * 
	 * @throws AgentException
	 *             Exception in construction of the agent.
	 */
	public TimerAgent() throws AgentException {
		this.syndicatedAgents = new AgentTableHelper();
		// Enables object communication with unlimited queue size.
		this.setEnabledO2ACommunication(true, 0);
	}

	/**
	 * @see jade.core.Agent#setup()
	 */
	@Override
	protected void setup() {
		addBehaviour(new TimerCyclicBehaviour());
	}

	/**
	 * Syndicates the specified agent.
	 * 
	 * @param agentName
	 *            Name of the agent to syndicate.
	 * @param aid
	 *            AID of the agent to syndicate.
	 */
	public void addSyndication(final String agentName, final AID aid) {
		if (!this.syndicatedAgents.contains(agentName)) {
			this.syndicatedAgents.addNode(agentName, aid);
			eotSent++;
		}
	}

	/**
	 * Sets End-Of-Tick flag to the specified agent.
	 * 
	 * @param name
	 *            Name of the syndicated agent.
	 */
	public void setEOT(final String name) {
		this.syndicatedAgents.setEOT(name);
		eotSent++;
	}

	/**
	 * When all active agents have sent EOT this agent is ready for a new tick.
	 * 
	 * @return {@link List} of agents in case the agent is ready or
	 *         <code>null</code> if it is not.
	 */
	public List<AID> readyForNextTick() {
		List<AID> l = this.syndicatedAgents.getActive();
		if (l.size() == eotSent) {
			return l;
		}
		return null;
	}

	/**
	 * @return the endOfExecution
	 */
	public boolean isEndOfExecution() {
		return endOfExecution;
	}

	/**
	 * @param endOfExecution
	 *            the endOfExecution to set
	 */
	public void setEndOfExecution(final boolean endOfExecution) {
		this.endOfExecution = endOfExecution;
	}

	/**
	 * @return the simulationHorizon
	 */
	public int getSimulationHorizon() {
		return simulationHorizon;
	}

	/**
	 * @param simulationHorizon
	 *            the simulationHorizon to set
	 */
	public void setSimulationHorizon(final int simulationHorizon) {
		this.simulationHorizon = simulationHorizon;
	}

	/**
	 * @return the currentTick
	 */
	public long getCurrentTick() {
		return currentTick;
	}

	/**
	 * Increases the time tick.
	 */
	public void incTick() {
		this.currentTick++;
	}
}
